#include "ActionEncrypt.h"
#include "EncryptionManager.h"
#include "SelectionManager.h"
#include "VectorUtil.h"
#include "qzip.h"
#include "Base64Encoder.h"
#include "SymmetricKeyFile.h"

#include <QDebug>
#include <QDate>
#include <QTime>
#include <QFile>
#include <vector>
#include <sstream>
#include <list>
#include <assert.h>

using namespace kryptos::cryptography;
using namespace kryptos::selection;
using namespace kryptos::util;
using namespace kryptos::entities;

namespace kryptos { namespace actions {

ActionEncrypt::ActionEncrypt(std::vector<unsigned char> selection,
                             SourceType                 sourceType,
                             RecipientVector            recipientsKeys,
                             SymmetricKeyInfoList       symmetricKeys)
    : m_selection(selection)
    , m_sourceType(sourceType)
    , m_recipients(recipientsKeys)
    , m_symmetricKeys(symmetricKeys)
{
    assert(!m_selection.empty());
    assert(m_sourceType == FILE || m_sourceType == SELECTION);
    assert(!m_recipients.empty());

    Prepare();
}

ActionEncrypt::~ActionEncrypt()
{

}

bool ActionEncrypt::Prepare()
{
    return true;
}

std::vector<unsigned char> ActionEncrypt::encryptedSelection()
{
    return m_encryptedSelection;
}

bool ActionEncrypt::Cleanup()
{
    QFile::remove(m_compressedFileName.c_str());
    QFile::remove(m_encryptedFileTmp.c_str());

    return true;
}

void ActionEncrypt::RunAction()
{
    try
    {
        if (m_sourceType == FILE)
            encryptFiles();
        else
            encryptSelection();
    }
    catch (...)
    {
        //error signal
    }

    emit actionEnded(true);

    Cleanup();
}

void ActionEncrypt::encryptFiles()
{
    QStringList files;
    foreach(std::string str, VectorUtil::toStringList(m_selection))
        files << QString(str.c_str());

    m_compressedFileName = files.size() > 1
            ? QFileInfo(files.first()).canonicalPath().toStdString() + "/" +
                                      QDate::currentDate().toString("yy-MM-dd").toStdString() +
                                      QTime::currentTime().toString("hh-mm-ss").toStdString() + ".qz"
                                    : files.first().toStdString() + ".qz";

    qzip::QZip::zipFiles(files, m_compressedFileName.c_str());

    m_encryptedFile = m_compressedFileName.substr(0, m_compressedFileName.find(".qz")).append(".k");

    EncryptionManager encrypter;

    if (!m_symmetricKeys.empty())
    {
        SymmetricKeyInfo symkeyinfo = m_symmetricKeys.front();
        SymmetricKeyFile symkey(symkeyinfo.id(), symkeyinfo.keyfile());
        symkey.setOffset(symkeyinfo.offset());
        encrypter.encryptWithHybridFormat(m_compressedFileName, m_encryptedFile, m_recipients, symkey);
    }
    else
    {
        encrypter.encryptWithPublicKey(m_compressedFileName, m_encryptedFile, m_recipients);
    }
}

void ActionEncrypt::encryptSelection()
{
    m_compressedFileName   = QDir::current().canonicalPath().toStdString() + "/" + QDate::currentDate().toString("yy-MM-dd").toStdString() + QTime::currentTime().toString("hh-mm-ss").toStdString() + ".qz";
    QString selectionFileTmp = QDir::currentPath() + "/" + QDate::currentDate().toString("yy-MM-dd") + QTime::currentTime().toString("hh-mm-ss");

    QFile tempFile(selectionFileTmp);
    tempFile.open(QIODevice::ReadWrite);
    tempFile.write((char*)m_selection.data(), m_selection.size());
    tempFile.flush();
    tempFile.close();

    QStringList files;
    files << tempFile.fileName();

    qzip::QZip::zipFiles(files, m_compressedFileName.c_str());

    m_encryptedFileTmp = m_compressedFileName.substr(0, m_compressedFileName.find(".qz")).append(".k");

    EncryptionManager encrypter;

    if (!m_symmetricKeys.empty())
    {
        SymmetricKeyInfo symkeyinfo = m_symmetricKeys.front();
        SymmetricKeyFile symkey(symkeyinfo.id(), symkeyinfo.keyfile());
        symkey.setOffset(symkeyinfo.offset());
        encrypter.encryptWithHybridFormat(m_compressedFileName, m_encryptedFileTmp, m_recipients, symkey);
    }
    else
    {
        encrypter.encryptWithPublicKey(m_compressedFileName, m_encryptedFileTmp, m_recipients);
    }

    QFile encryptedFile(m_encryptedFileTmp.c_str());
    encryptedFile.open(QFile::ReadOnly);

    QByteArray encryptedselection(encryptedFile.readAll());
    m_encryptedSelection.assign(encryptedselection.data(), encryptedselection.data()+encryptedselection.size());

    QFile::remove(selectionFileTmp);
}

}}
